/* 
 * File:   ipd_filter.cpp
 * Author: dima
 * 
 * Created on 27 января 2015 г., 23:06
 */

#include "ipd_filter.h"
#include "ipd_exception.h"
namespace ipd
{

ipd_filter::ipd_filter(ipd_img &img) : original_image(img)
{
    sum = new int[sz_RGB];
    pixel = new unsigned char[sz_RGB];
    sum_elements_mask = 0;
    width_mask = height_mask = 0;
    mask = NULL;
}

ipd_filter::~ipd_filter()
{
    delete []sum;
    delete []pixel;
    delete_mask();
}

void ipd_filter::init(int w_mask, int h_mask, int *maska)//object initialization
{
    if ((w_mask-1) % 2 != 0 || (h_mask-1) % 2 != 0)
        throw ipd_exception(std::string("The dimension of the mask must be odd"), std::string("ipd_filter"));
    img_model = original_image.get_color_type();
    width_image = original_image.get_width();
    height_image = original_image.get_height();
    width_mask = w_mask;
    height_mask = h_mask;
    delete_mask();
    mask = new int [width_mask * height_mask];
    sum_elements_mask = 0;
    for (int i = 0; i < width_mask * height_mask; i++)
    {
        mask[i] = maska[i];
        sum_elements_mask += mask[i];
    }

}

void ipd_filter::convert_image(ipd_img &img)//convert Image
{
    img.init(width_image, height_image, img_model);
    int index_x, index_y;
    unsigned char *ch;
    int i, j, k, p;
    for (j = 0; j < height_image; j++)
    {
        for (i = 0; i < width_image; i++)
        {
            for (k = 0; k < sz_RGB; sum[k++] = 0);
            for (k = 0; k < height_mask; k++)
            {
                for (p = 0; p < width_mask; p++)
                {
                    index_x = i + p;
                    index_y = j + k;
                    if (index_x < 0 || index_x >= width_image || index_y < 0 || index_y >= height_image)
                        continue;
                    ch = original_image.get_color(index_x, index_y);
                    multiply(mask[k * width_mask + p], ch);
                }
            }
            get_pixel(pixel);
            img.set_color(i, j, pixel);
        }
    }
}

void ipd_filter::multiply(double mask, unsigned char *pixel)//multiply the pixel on the mask weights
{
    switch (img_model)
    {
    case ipd::tp_RGB:
    {
        for (int i = 0; i < sz_RGB; i++)
            sum[i] += mask * *(pixel + i);
        break;
    }
    case ipd::tp_mono:
    {
        sum[0] += mask * *pixel;
        break;
    }
    }
}

void ipd_filter::get_pixel(unsigned char *pixel)//get normalized pixel
{
    switch (img_model)
    {
    case ipd::tp_RGB:
    {
        for (int i = 0; i < sz_RGB; i++)
            pixel[i] = sum[i] / (double) sum_elements_mask;
        break;
    }
    case ipd::tp_mono:
    {
        pixel[0] = sum[0] / (double) sum_elements_mask;
        break;
    }
    }
}

ipd_filter::ipd_filter(const ipd_filter& orig) : original_image(orig.original_image)
{
}

void ipd_filter::delete_mask()// delete mask
{
    if (mask != NULL)
        delete []mask;
    mask = NULL;
}


}